<?php
/**
 * Articles manager.
 *
 * @author Martin "DevelX" Jurča
 */
class Articles extends Module {
    protected $name = 'Articles';
    protected $administrable = true;
    protected $version = '2010-08-17';
    protected $details = array('dependencies' => array('Categories'),
            'observes' => array('Articles'));

    const ARTICLES_TABLE  = 'articles';
    const ARTICLES_CATEGORIES = 'articlesCategories';

    private $articleTable = array('id' => 'iPN+', 'title' => "v'512'N",
            'subtitle' => "v'512'", 'lang' => "v'5'", 'image' => 'i',
            'header' => 'T', 'text' => 'TN', 'created' => 'iN', 'edited' =>
            'i', 'source' => 's', 'author' => 's');
    private $categoryTable = array('article' => 'iNI', 'category' => 'iNI');

    private $articleRecord = array('table' => self::ARTICLES_TABLE, 'data' =>
            array());
    private $categoryRecord = array('table' => self::ARTICLES_CATEGORIES,
            'data' => array());

    private $filesRoot;
    private $categoryRoot;

    private $previewSize = 200;
    private $itemsOnPage = 10;

    public function  __construct(DBAPI $dbapi, RecordList $recordList) {
        parent::__construct($dbapi, $recordList);
        $this->articleRecord['properties'] = $this->articleTable;
        $this->categoryRecord['properties'] = $this->categoryTable;
        $settings = @unserialize(file_get_contents($this->getDir(
                '/settings')));
        if ($settings !== false) {
            $this->filesRoot = $settings['filesRoot'];
            $this->categoryRoot = $settings['categoryRoot'];
        }
    }

    public function install() {
        $this->dbdriver->createTable(self::ARTICLES_TABLE,
                $this->articleTable);
        $this->dbdriver->createTable(self::ARTICLES_CATEGORIES,
                $this->categoryTable);
        Modules::getModule('Users')->registerRights($this->name,
                $this->getRights());
        FTP::createFile($this->getDir('/settings', true));
        $file = @fopen($this->getDir('/settings'), 'w');
        if (!is_resource($file)) {
            return false;
        }
        @fwrite($file, serialize(array('filesRoot' => 0, 'categoryRoot' =>
                0)));
        @fclose($file);
        return true;
    }

    public function uninstall() {
        $this->dbdriver->dropTable(self::ARTICLES_TABLE);
        $this->dbdriver->dropTable(self::ARTICLES_CATEGORIES);
        FTP::deleteFile($this->getDir('/settings', true));
        return true;
    }

    public function initDisplay($param = null) {
        $details = Modules::getModule('View')->getUrl();
        if (count($details) == 2) {
            if ($details[1] == 'add-article') {
                Modules::getModule('View')->addJS(Config::WEB_DIR .
                        '/utils/tiny_mce/tiny_mce.js');
                Modules::getModule('View')->addJS(Config::WEB_DIR .
                        $this->getDir('/admin.js', true));
            }
        } elseif ((Kernel::getMode() == Kernel::ADMIN) &&
                (count($details) == 3)) {
            Modules::getModule('View')->addJS(Config::WEB_DIR .
                        '/utils/tiny_mce/tiny_mce.js');
            Modules::getModule('View')->addJS(Config::WEB_DIR . $this->getDir(
                        '/admin.js', true));
        }
    }

    public function &onDelete(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('Articles',
                'delete articles')) {
            Modules::getModule('View')->addMessage($this->lang(
                    'insufficentRights'), View::MSG_ERROR);
            return $result;
        }
        $id = (int) substr($details, 0, -1);
        $this->dbdriver->delete($this->categoryRecord['table'],
                "`article` = $id");
        $this->dbdriver->delete($this->articleRecord['table'], "`id` = $id");
        return $result;
    }

    public function &onCreateArticle(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('Articles',
                'create articles')) {
            Modules::getModule('View')->addMessage($this->lang(
                    'insufficentRights'), View::MSG_ERROR);
            return $result;
        }
        $article = $this->articleRecord;
        $article['data'] = array('title' => $details['title'], 'subtitle' =>
                $details['subtitle'], 'lang' => $details['lang'], 'header' =>
                $details['header'], 'text' => $details['text'], 'source' =>
                $details['articleSource'], 'author' => $details['author'],
                'created' => time());
        $image = &Modules::getModule('Files')->uploadFiles($_FILES,
                $this->filesRoot);
        if (count($image) > 0) {
            $article['data']['image'] = $image[0]['data']['id'];
        }
        $this->dbapi->save($article);
        if (isset($details['category']) && is_array($details['category'])) {
            foreach ($details['category'] as $categoryId) {
                $category = $this->categoryRecord;
                $category['data'] = array('article' => $article['data']['id'],
                        'category' => $categoryId);
                $this->dbapi->save($category);
            }
        }
        return $result;
    }

    public function &onEditArticle(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('Articles',
                'edit articles')) {
            Modules::getModule('View')->addMessage($this->lang(
                    'insufficentRights'), View::MSG_ERROR);
            return $result;
        }
        $this->dbdriver->delete($this->categoryRecord['table'],
                '`article` = ' . (int) $details['id']);
        if (isset($details['category']) && is_array($details['category'])) {
            foreach ($details['category'] as $categoryId) {
                $category = $this->categoryRecord;
                $category['data'] = array('article' => $details['id'],
                        'category' => $categoryId);
                $this->dbapi->save($category);
            }
        }
        $article = $this->articleRecord;
        $article['data']['id'] = $details['id'];
        $this->dbapi->refresh($article);
        $article['data'] = array('id' => $details['id'], 'title' =>
                $details['title'], 'subtitle' => $details['subtitle'],
                'lang' => $details['lang'], 'header' => $details['header'],
                'text' => $details['text'], 'source' =>
                $details['articleSource'], 'author' => $details['author'],
                'image' => $article['data']['image'], 'created' =>
                $article['data']['created'], 'edited' => time());
        if (isset($details['removeImage'])) {
            $article['data']['image'] = null;
        }
        $image = &Modules::getModule('Files')->uploadFiles($_FILES,
                $this->filesRoot);
        if (count($image) > 0) {
            $article['data']['image'] = $image[0]['data']['id'];
        }
        $this->dbapi->update($article);
        return $result;
    }

    public function &onSettings(&$details, $source) {
        $result = null;
        Kernel::setRedirect($this->getLink());
        if (!Modules::getModule('Users')->checkRights('Articles', 'settings')) {
            Modules::getModule('View')->addMessage($this->lang(
                    'insufficentRights'), View::MSG_ERROR);
            return $result;
        }
        $this->filesRoot = $details['filesRoot'];
        $this->categoryRoot = $details['categoryRoot'];
        $file = @fopen($this->getDir('/settings'), 'w');
        if (!is_resource($file)) {
            return $result;
        }
        @fwrite($file, serialize(array('filesRoot' => $this->filesRoot,
                'categoryRoot' => $this->categoryRoot)));
        @fclose($file);
        return $result;
    }

    /**
     * Displays list of articles in certain category.
     *
     * @param int $category CategoryID number
     */
    public function displayPublicList($category) {
        $cols = array('article');
        $articlesIds = &$this->dbdriver->select(self::ARTICLES_CATEGORIES,
                $cols, '`category` = ' . (int) $category);
        foreach ($articlesIds as &$articleId) {
            $articleId = $articleId['article'];
        }
        $params = array('filter' => '`id` IN (' . implode(',', $articlesIds) .
                ')');
        if (count($articlesIds) > 0) {
            $articles = $this->recordList->getList($this->articleRecord,
                    $params);
        } else {
            $articles = array();
        }
        foreach ($articles as &$item) {
            $params = array('title' => $item['title'], 'text' => $this->
                    getStringPreview(strip_tags($item['header'] .
                    $item['text']), $this->previewSize), 'more' => $this->
                    lang('more'), 'url' => $this->getLink(Kernel::createUrl(
                    $item['title']) . '-' . $item['id']) . '/');
            $this->template('articlepreview', $params);
        }
    }

    public function displayPublicArticleText($id) {
        $article = $this->articleRecord;
        $article['data']['id'] = (int) $id;
        $this->dbapi->refresh($article);
        $params = array('article' => $article['data']);
        $this->template('text', $params);
    }

    /**
     * Displays specific article with given ID.
     *
     * @param int $id Artile ID number.
     */
    public function displayPublicArticle($id) {
        $article = $this->articleRecord;
        $article['data']['id'] = (int) substr($id, strripos($id, '-') + 1);
        $this->dbapi->refresh($article);
        $image = &Modules::getModule('Files')->getFile(
                $article['data']['image']);
        if (is_file(Config::ROOT . '/modules/Files/uploaded/' .
                    $image['data']['localName'])) {
            $details = getimagesize(Config::ROOT . '/modules/Files/uploaded/' .
                    $image['data']['localName']);
            if ($details[0] > 560) {
                $image = array(array('cmd' => 'import', 0 => Config::ROOT .
                        '/modules/Files/uploaded/' .
                        $image['data']['localName']), array('cmd' => 'resize',
                        0 => 560, 1 => $details[1], 2 => false, 3 => -1, 4 =>
                        true));
                $image = Kernel::getImageLink($image);
            } else {
                $image = Config::WEB_DIR . '/modules/Files/uploaded/' .
                        $image['data']['localName'];
            }
        } else {
            $image = false;
        }
        $params = array('title' => $article['data']['title'], 'subtitle' =>
                $article['data']['subtitle'], 'header' =>
                $article['data']['header'], 'text' =>
                $article['data']['text'], 'image' => $image);
        $this->template('article', $params);
    }

    public function displayPublicBrowse($category = null, $page = 1) {
        if (!is_numeric($category)) {
            $cond = '';
        } else {
            $cols = array('article');
            $ids = &$this->dbdriver->select(self::ARTICLES_CATEGORIES, $cols,
                    '`category` = ' . (int) $category);
            foreach ($ids as &$id) {
                $id = $id['article'];
            }
            $cond = '`id` IN (' . implode(',', $ids) . ')';
        }
        $order = array('!id');
        $cols = array('COUNT(*)');
        $pages = &$this->dbdriver->select(self::ARTICLES_TABLE, $cols, $cond);
        $pages = max(1, ceil($pages[0][$cols[0]] / $this->itemsOnPage));
        $page = max(1, min($page, $pages));
        $cols = array('id', 'title', 'header', 'text');
        $articles = &$this->dbdriver->select(self::ARTICLES_TABLE, $cols,
                $cond, $order, ($page - 1) * $this->itemsOnPage,
                $this->itemsOnPage);
        foreach ($articles as &$article) {
            $article['text'] =
                    $this->getStringPreview(strip_tags($article['header'] .
                    $article['text']), $this->previewSize);
            $params = array_merge($article, array('url' =>
                    $this->getLink('article/' .
                    Kernel::createUrl($article['title']) . '-' .
                    $article['id'] . '/')));
            $this->template('articlepreview', $params);
        }
        $params = array('linkPreffix' => $this->getLink('browse/' .
                ($category ? "$category/" : '-/')), 'linkSuffix' => '/',
                'current' => $page, 'count' => $pages);
        $this->template('pages', $params);
    }

    /**
     * Displayes preview of newest articles available.
     *
     * @param mixed Category ID number to display.
     */
    public function displayPublicPreview($category = null) {
        $params = array('order' => array('!id'), 'count' => 3);
        if (is_numeric($category)) {
            $cols = array('article');
            $articlesIDs = &$this->dbdriver->select(self::ARTICLES_CATEGORIES,
                    $cols, '`category` = ' . (int) $category);
            foreach ($articlesIDs as &$articleID) {
                $articleID = $articleID['article'];
            }
            $params['filter'] = '`id` IN (' . implode(',', $articlesIDs) . ')';
            $articles = &$this->recordList->getList($this->articleRecord,
                    $params);
        } else {
            $article = &$this->recordList->getList($this->articleRecord,
                    $params);
        }
        foreach ($articles as &$article) {
            $article['text'] =
                    strip_tags($article['header'] . $article['text']);
            $params = array('title' => $article['title'], 'text' =>
                    $this->getStringPreview($article['text'],
                    $this->previewSize) . '...', 'url' =>
                    $this->getLink('article/' . Kernel::createUrl(
                    $article['title']) . '-' . $article['id'] . '/'),
                    'more' => $this->lang('more'));
            $this->template('articlepreview', $params);
        }
        echo '<p><a href="' . $this->getLink('browse/' .
                ($category ? "$category/" : '')) . '">' .
                $this->lang('olderArtices') . '</a></p>';
    }

    /**
     * Returns preview of given string string long at least $count bytes long
     * ending with complete word (does not split the last word).
     *
     * @param String $string String of which preview should be created.
     * @param int $count At least how long the preview should be.
     * @return String Preview of the string.
     */
    private function getStringPreview($string, $count) {
        if (strlen($string) <= $count) {
            return $string;
        }
        return substr($string, 0, strpos($string, ' ', $count));
    }

    public function displayAdminSettings() {
        if (!Modules::getModule('Users')->checkRights('Articles', 'settings')) {
            return;
        }
        $categories = &Modules::getModule('Categories')->getCategoryList();
        $fileCategories = &Modules::getModule('Files')->getCategories();
        $params = array('fileRootLabel' => $this->lang('fileRoot'),
                'categoryRootLabel' => $this->lang('categoryRoot'),
                'fileRoot' => $this->filesRoot, 'categoryRoot' =>
                $this->categoryRoot, 'categories' => $categories, 'files' =>
                $fileCategories, 'save' => $this->lang('save'), 'formStart' =>
                $this->getForm('settings', true, 'Articles'), 'settings' =>
                $this->lang('settings'));
        $this->template('settings', $params);
    }

    public function displayAdminEdit($id) {
        if (!Modules::getModule('Users')->checkRights('Articles',
                'edit articles')) {
            return;
        }
        $article = $this->articleRecord;
        $article['data']['id'] = (int) $id;
        $this->dbapi->refresh($article);
        $categories = &Modules::getModule('Categories')->getCategoryList(
                $this->categoryRoot);
        $params = array('filter' => '`article` = ' . $article['data']['id']);
        $articleCategories = $this->recordList->getList($this->categoryRecord,
                $params);
        foreach ($categories as &$category) {
            $category = $category['data'];
            $selected = false;
            foreach ($articleCategories as $articleCategory) {
                if ($articleCategory['category'] == $category['id']) {
                    $selected = true;
                    break;
                }
            }
            $category['selected'] = $selected;
        }
        if ($article['data']['image'] != null) {
            $article['data']['image'] = Modules::getModule('Files')->getFile(
                    $article['data']['image']);
            $article['data']['image'] = Config::ROOT .
                    '/modules/Files/uploaded/' .
                    $article['data']['image']['data']['localName'];
            $params = array(array('cmd' => 'import', 0 =>
                    $article['data']['image']), array('cmd' => 'resize', 0 =>
                    100, 1 => 100, 2 => false, 3 => -1, 4 => true));
            $article['data']['image'] = Kernel::getImageLink($params);
        }
        $params = array('formStart' => $this->getForm('editArticle', true,
                'Articles'), 'editArticle' => $this->lang('editArticle'),
                'title' => $this->lang('title'), 'subtitle' =>
                $this->lang('subtitle'), 'language' => $this->lang('language'),
                'image' => $this->lang('image'), 'categoriesLabel' =>
                $this->lang('categories'), 'header' => $this->lang('header'),
                'text' => $this->lang('text'), 'source' =>
                $this->lang('source'), 'author' => $this->lang('author'),
                'save' => $this->lang('save'), 'categories' => $categories,
                'article' => $article['data'], 'savedImage' =>
                $this->lang('savedImage'), 'deleteImage' =>
                $this->lang('deleteImage'), 'fileCategoryId' =>
                $this->filesRoot);
        $this->template('edit', $params);
    }

    public function displayAdminIndex() {
        $params = array();
        $articles = &$this->recordList->getList($this->articleRecord, $params);
        foreach ($articles as &$article) {
            $article['edit'] = $this->getLink("edit/{$article['id']}/");
            $article['delete'] = $this->getLink("{$article['id']}/",
                    'delete');
        }
        $params = array('articles' => $articles, 'list' =>
                $this->lang('articles'), 'edit' => $this->lang('edit'),
                'delete' => $this->lang('delete'));
        $this->template('browse', $params);
    }

    public function displayAdminAddArticle() {
        if (!Modules::getModule('Users')->checkRights('Articles',
                'create articles')) {
            return;
        }
        $categories = Modules::getModule('Categories')->getCategoryList(
                $this->categoryRoot);
        foreach ($categories as &$category) {
            $category = $category['data'];
        }
        $user = &Modules::getModule('Users')->getUser();
        $params = array('formStart' => $this->getForm('createArticle', true,
                'Articles'), 'addArticle' => $this->lang('addArticleForm'),
                'title' => $this->lang('title'), 'subtitle' =>
                $this->lang('subtitle'), 'language' => $this->lang('language'),
                'image' => $this->lang('image'), 'categoriesLabel' =>
                $this->lang('categories'), 'addCategory' =>
                $this->lang('addCategory'), 'header' => $this->lang('header'),
                'text' => $this->lang('text'), 'create' =>
                $this->lang('create'), 'categories' => $categories, 'source' =>
                $this->lang('source'), 'author' => $this->lang('author'),
                'login' => $user['data']['login'], 'fileCategoryId' =>
                $this->filesRoot);
        $this->template('add', $params);
    }

    /**
     * Displays module administration submenu.
     *
     */
    public function displayAdminSubmenu() {
        $params = array('menu' => array(array('href' => $this->getLink(),
                'title' => $this->lang('listTitle'), 'label' =>
                $this->lang('list')), array('href' =>
                $this->getLink('add-article/'), 'title' =>
                $this->lang('addArticleTitle'), 'label' =>
                $this->lang('addArticle')), array('href' =>
                $this->getLink('settings/'), 'title' =>
                $this->lang('settingsTitle'), 'label' =>
                $this->lang('settings'))));
        $this->template('submenu', $params);
    }
}
?>
